invalidate是用来进行view的重绘的,它一般会导致onDraw的调用(对于ViewGroup容器来说它并不一定会调用onDraw)以使View改变自身内容,但是如果当view的大小尺寸发生了变化,此时就需要requestLayout对view进行布局请求。比如当view设置了布局参数后就需要进行布局请求。但需要注意的是requestLayout并不保证onDraw会调用,它只负责完成布局请求,调不调用onDraw取决于view的内容是否改变。所以一般情况下requestLayout和invalidate是结合着使用的。
1 | public void setLayoutParams(ViewGroup.LayoutParams params) { |
1 | // /frameworks/base/core/java/android/view/View.java |
requestLayout是从View开始,它首先判断的当前viewRoot是否正在进行layout,如果是,则发送请求给ViewRoot,告诉它当前view需要进行layout。否则为view打上PFLAG_FORCE_LAYOUT和PFLAG_INVALIDATED标记,然后调用parent的requestLayout,这里parent即它的父view,可以是ViewGroup也可以是ViewRoot,其中ViewGroup没有覆盖requestLayout,那么依然是调用View的requestLayout。这实际上是一个递归调用为父view打上请求布局的标记。直到ViewRootImpl。
1 | ///frameworks/base/core/java/android/view/ViewRootImpl.java |
ViewRootImpl的requestLayout中设置mLayoutRequested为true,然后开启请求布局。
1 | private void performTraversals() { |
mLayoutRequested 在requestLayout中设置为true,mStopped表示当前view树所在的window状态不是停止的,一般为false,那么layoutRequested为true,didLayout为true。那么分别执行performMeasure和performLayout,下面我们分别分析。
1 | private void performMeasure(int childWidthMeasureSpec, int childHeightMeasureSpec) { |
ViewRootImpl的performMeasure执行view的measure方法进行测量。
1 | public final void measure(int widthMeasureSpec, int heightMeasureSpec) { |
由于mPrivateFlags在requestLayout中设置了PFLAG_FORCE_LAYOUT,所有清除PFLAG_MEASURED_DIMENSION_SET的标记,这个标记用于检测是否调用setMeasuredDimension,同时打上PFLAG_LAYOUT_REQUIRED标记,表示请求布局。
1 | private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth, |
performLayout负责执行viewlayout过程,同时对请求布局的view也执行requstLayout。这里host就是view树的根节点,即DecorView,它是个FrameLayout。所以我们看看ViewGroup的layout。
1 |
|
viewGroup调用view的layout
1 | public void layout(int l, int t, int r, int b) { |
由于在measure过程中设置了PFLAG_LAYOUT_REQUIRED标记,那么就会调用onLayout来进行view的布局过程,这个过程完成后,清理PFLAG_LAYOUT_REQUIRED和PFLAG_FORCE_LAYOUT标记表示布局过程完成了。这里需要注意的是view在测量后大小可能发生变化,这时候通过setFrame设置其边框时会调用invalidate的调用,因此可能会导致onDraw的调用。